home *** CD-ROM | disk | FTP | other *** search
/ Whiteline: delta / whiteline CD Series - delta.iso / document / hypertxt / ximgtool / encoders.c next >
C/C++ Source or Header  |  1995-11-25  |  34KB  |  1,163 lines

  1. #include "imgcodec.h"
  2.  
  3. /* Local extension of public image buffer struct for encoding. */
  4.  
  5. typedef struct ibuf
  6. {
  7.   IBUFPUB pub;
  8.   char *line_adr;
  9.   long length;
  10.   long byte_width;    /* Only used in Level-1 encoding. */
  11.   char *image_adr;
  12.   char *image_ptr;    /* Only used in Level-3 encoding. */
  13.   void (*raw_encode)(struct ibuf *ip);
  14.   void (*user_exit)(void);
  15.   FBUFPUB *output;
  16.   short out_vrc;
  17.   short height;
  18.   char data[0];
  19. }
  20. IBUF;
  21.  
  22. /* Forward declarations of local functions. */
  23.  
  24. static void level_3_putline(IBUF *ip);
  25. static void level_2_putline(IBUF *ip);
  26. static void level_1_putline(IBUF *ip);
  27.  
  28. static void l_3_p_1_encode(IBUF *ip);
  29. static void l_3_p_2_encode(IBUF *ip);
  30. static void l_2_p_1_encode(IBUF *ip);
  31. static void l_2_p_2_encode(IBUF *ip);
  32. static void l_1_p_1_encode(IBUF *ip);
  33. static void l_1_p_2_encode(IBUF *ip);
  34.  
  35. /* Generic initialization function for encoding.
  36.  * Causes all defined encoding functions to be linked to the caller.
  37.  * Returns a zero pointer if user_malloc failes.
  38.  * Otherwise the returned pointer has to be freed after
  39.  * processing by the 'complement' of user_malloc.
  40.  */
  41.  
  42. IBUFPUB *encode_init(IMG_HEADER *input_header, FBUFPUB *output,
  43.              void *(*user_malloc)(long size),
  44.              void (*user_exit)(void),
  45.              short out_lev, short out_pat)
  46. {
  47.   long byte_width, line_len, buf_len;
  48.   IBUF *image;
  49.  
  50.   byte_width = (input_header->sl_width + 7) >> 3;
  51.   line_len = byte_width * input_header->planes;
  52.   /* Alloc double line buffer for out_vrc handling (one line delay) */
  53.   buf_len = line_len << 1;
  54.   /* For Level-2 we need an additional line buffer for extended vrc
  55.    * handling.
  56.    */
  57.   if (out_lev == 2) buf_len += line_len;
  58.   else if (out_lev != 1)
  59.     /* Level-3 encoder requires a full image buffer. */
  60.     buf_len += line_len * input_header->sl_height;
  61.   image =
  62.     (*user_malloc)(sizeof(IBUF) + buf_len + input_header->pat_run);
  63.   if (image)
  64.   {
  65.     image->line_adr = image->pub.pbuf = image->data;
  66.     image->image_adr = image->data + (line_len << 1);
  67.     image->pub.pat_buf = image->data + buf_len;
  68.     image->pub.bytes_left = line_len;
  69.     image->length = line_len;
  70.     image->byte_width = byte_width;
  71.     image->pub.pat_run = input_header->pat_run;
  72.     image->height = input_header->sl_height;
  73.     image->pub.vrc = 1; image->pub.init = 0;
  74.     image->output = output; image->user_exit = user_exit;
  75.  
  76.     image->pub.put_line = (void (*)(IBUFPUB *))
  77.       (out_lev == 1 ? level_1_putline :
  78.        out_lev == 2 ? level_2_putline : level_3_putline);
  79.  
  80.     image->raw_encode =
  81.      out_lev == 1
  82.       ? (out_pat == 1 ? l_1_p_1_encode : l_1_p_2_encode)
  83.       :  out_lev == 2
  84.       ? (out_pat == 1 ? l_2_p_1_encode : l_2_p_2_encode)
  85.       : (out_pat == 1 ? l_3_p_1_encode : l_3_p_2_encode);
  86.   }
  87.   return &image->pub;
  88. }
  89.  
  90. /* Here are the special encode initialization functions.
  91.  * The reason for introducing them is, that an application usually
  92.  * needs only one encoder. The programmer has the freedom
  93.  * (or pain ;-) to decide. For instance, a snapshot utility is
  94.  * recommended to use a Level-2 encoder, because extended vrc
  95.  * may provide significant savings over Level-1, and Level-3 could
  96.  * rather fail in memory allocation (if Level-3 is nevertheless
  97.  * desired, there should be at least an alternative Level-2 mode
  98.  * built in to be used in case of Level-3 failing).
  99.  */
  100.  
  101. IBUFPUB *l3p2_encode_init(IMG_HEADER *input_header, FBUFPUB *output,
  102.               void *(*user_malloc)(long size),
  103.               void (*user_exit)(void))
  104. {
  105.   long byte_width, line_len, buf_len;
  106.   IBUF *image;
  107.  
  108.   byte_width = (input_header->sl_width + 7) >> 3;
  109.   line_len = byte_width * input_header->planes;
  110.   /* Alloc double line buffer for out_vrc handling (one line delay) */
  111.   buf_len = line_len << 1;
  112.   /* Level-3 encoder requires a full image buffer. */
  113.   buf_len += line_len * input_header->sl_height;
  114.   image =
  115.     (*user_malloc)(sizeof(IBUF) + buf_len + input_header->pat_run);
  116.   if (image)
  117.   {
  118.     image->line_adr = image->pub.pbuf = image->data;
  119.     image->image_adr = image->data + (line_len << 1);
  120.     image->pub.pat_buf = image->data + buf_len;
  121.     image->pub.bytes_left = line_len;
  122.     image->length = line_len;
  123.     image->pub.pat_run = input_header->pat_run;
  124.     image->height = input_header->sl_height;
  125.     image->pub.vrc = 1; image->pub.init = 0;
  126.     image->output = output; image->user_exit = user_exit;
  127.     image->pub.put_line = (void (*)(IBUFPUB *))level_3_putline;
  128.     image->raw_encode = l_3_p_2_encode;
  129.   }
  130.   return &image->pub;
  131. }
  132.  
  133. IBUFPUB *l3p1_encode_init(IMG_HEADER *input_header, FBUFPUB *output,
  134.               void *(*user_malloc)(long size),
  135.               void (*user_exit)(void))
  136. {
  137.   long byte_width, line_len, buf_len;
  138.   IBUF *image;
  139.  
  140.   byte_width = (input_header->sl_width + 7) >> 3;
  141.   line_len = byte_width * input_header->planes;
  142.   /* Alloc double line buffer for out_vrc handling (one line delay) */
  143.   buf_len = line_len << 1;
  144.   /* Level-3 encoder requires a full image buffer. */
  145.   buf_len += line_len * input_header->sl_height;
  146.   image =
  147.     (*user_malloc)(sizeof(IBUF) + buf_len + input_header->pat_run);
  148.   if (image)
  149.   {
  150.     image->line_adr = image->pub.pbuf = image->data;
  151.     image->image_adr = image->data + (line_len << 1);
  152.     image->pub.pat_buf = image->data + buf_len;
  153.     image->pub.bytes_left = line_len;
  154.     image->length = line_len;
  155.     image->pub.pat_run = input_header->pat_run;
  156.     image->height = input_header->sl_height;
  157.     image->pub.vrc = 1; image->pub.init = 0;
  158.     image->output = output; image->user_exit = user_exit;
  159.     image->pub.put_line = (void (*)(IBUFPUB *))level_3_putline;
  160.     image->raw_encode = l_3_p_1_encode;
  161.   }
  162.   return &image->pub;
  163. }
  164.  
  165. IBUFPUB *l2p2_encode_init(IMG_HEADER *input_header, FBUFPUB *output,
  166.               void *(*user_malloc)(long size),
  167.               void (*user_exit)(void))
  168. {
  169.   long byte_width, line_len, buf_len;
  170.   IBUF *image;
  171.  
  172.   byte_width = (input_header->sl_width + 7) >> 3;
  173.   line_len = byte_width * input_header->planes;
  174.   /* Alloc double line buffer for out_vrc handling (one line delay) */
  175.   buf_len = line_len << 1;
  176.   /* For Level-2 we need an additional line buffer for extended vrc
  177.    * handling.
  178.    */
  179.   buf_len += line_len;
  180.   image =
  181.     (*user_malloc)(sizeof(IBUF) + buf_len + input_header->pat_run);
  182.   if (image)
  183.   {
  184.     image->line_adr = image->pub.pbuf = image->data;
  185.     image->image_adr = image->data + (line_len << 1);
  186.     image->pub.pat_buf = image->data + buf_len;
  187.     image->pub.bytes_left = line_len;
  188.     image->length = line_len;
  189.     image->pub.pat_run = input_header->pat_run;
  190.     image->height = input_header->sl_height;
  191.     image->pub.vrc = 1; image->pub.init = 0;
  192.     image->output = output; image->user_exit = user_exit;
  193.     image->pub.put_line = (void (*)(IBUFPUB *))level_2_putline;
  194.     image->raw_encode = l_2_p_2_encode;
  195.   }
  196.   return &image->pub;
  197. }
  198.  
  199. IBUFPUB *l2p1_encode_init(IMG_HEADER *input_header, FBUFPUB *output,
  200.               void *(*user_malloc)(long size),
  201.               void (*user_exit)(void))
  202. {
  203.   long byte_width, line_len, buf_len;
  204.   IBUF *image;
  205.  
  206.   byte_width = (input_header->sl_width + 7) >> 3;
  207.   line_len = byte_width * input_header->planes;
  208.   /* Alloc double line buffer for out_vrc handling (one line delay) */
  209.   buf_len = line_len << 1;
  210.   /* For Level-2 we need an additional line buffer for extended vrc
  211.    * handling.
  212.    */
  213.   buf_len += line_len;
  214.   image =
  215.     (*user_malloc)(sizeof(IBUF) + buf_len + input_header->pat_run);
  216.   if (image)
  217.   {
  218.     image->line_adr = image->pub.pbuf = image->data;
  219.     image->image_adr = image->data + (line_len << 1);
  220.     image->pub.pat_buf = image->data + buf_len;
  221.     image->pub.bytes_left = line_len;
  222.     image->length = line_len;
  223.     image->pub.pat_run = input_header->pat_run;
  224.     image->height = input_header->sl_height;
  225.     image->pub.vrc = 1; image->pub.init = 0;
  226.     image->output = output; image->user_exit = user_exit;
  227.     image->pub.put_line = (void (*)(IBUFPUB *))level_2_putline;
  228.     image->raw_encode = l_2_p_1_encode;
  229.   }
  230.   return &image->pub;
  231. }
  232.  
  233. IBUFPUB *l1p2_encode_init(IMG_HEADER *input_header, FBUFPUB *output,
  234.               void *(*user_malloc)(long size),
  235.               void (*user_exit)(void))
  236. {
  237.   long byte_width, line_len, buf_len;
  238.   IBUF *image;
  239.  
  240.   byte_width = (input_header->sl_width + 7) >> 3;
  241.   line_len = byte_width * input_header->planes;
  242.   /* Alloc double line buffer for out_vrc handling (one line delay) */
  243.   buf_len = line_len << 1;
  244.   image =
  245.     (*user_malloc)(sizeof(IBUF) + buf_len + input_header->pat_run);
  246.   if (image)
  247.   {
  248.     image->line_adr = image->pub.pbuf = image->data;
  249.     image->image_adr = image->pub.pat_buf = image->data + buf_len;
  250.     image->pub.bytes_left = line_len;
  251.     image->length = line_len;
  252.     image->byte_width = byte_width;
  253.     image->pub.pat_run = input_header->pat_run;
  254.     image->height = input_header->sl_height;
  255.     image->pub.vrc = 1; image->pub.init = 0;
  256.     image->output = output; image->user_exit = user_exit;
  257.     image->pub.put_line = (void (*)(IBUFPUB *))level_1_putline;
  258.     image->raw_encode = l_1_p_2_encode;
  259.   }
  260.   return &image->pub;
  261. }
  262.  
  263. IBUFPUB *l1p1_encode_init(IMG_HEADER *input_header, FBUFPUB *output,
  264.               void *(*user_malloc)(long size),
  265.               void (*user_exit)(void))
  266. {
  267.   long byte_width, line_len, buf_len;
  268.   IBUF *image;
  269.  
  270.   byte_width = (input_header->sl_width + 7) >> 3;
  271.   line_len = byte_width * input_header->planes;
  272.   /* Alloc double line buffer for out_vrc handling (one line delay) */
  273.   buf_len = line_len << 1;
  274.   image =
  275.     (*user_malloc)(sizeof(IBUF) + buf_len + input_header->pat_run);
  276.   if (image)
  277.   {
  278.     image->line_adr = image->pub.pbuf = image->data;
  279.     image->image_adr = image->pub.pat_buf = image->data + buf_len;
  280.     image->pub.bytes_left = line_len;
  281.     image->length = line_len;
  282.     image->byte_width = byte_width;
  283.     image->pub.pat_run = input_header->pat_run;
  284.     image->height = input_header->sl_height;
  285.     image->pub.vrc = 1; image->pub.init = 0;
  286.     image->output = output; image->user_exit = user_exit;
  287.     image->pub.put_line = (void (*)(IBUFPUB *))level_1_putline;
  288.     image->raw_encode = l_1_p_1_encode;
  289.   }
  290.   return &image->pub;
  291. }
  292.  
  293. /* Here come the local functions for encode processing. */
  294.  
  295. static void l_3_p_2_encode(IBUF *ip)
  296. {
  297.   char cdata, c_val, *line_buf, *line_ptr, *endl_buf;
  298.   long s_save, p_save, v_save, buf_offs;
  299.   char *srp, *prp, *vrp;
  300.   FBUFPUB *output;
  301.  
  302.   endl_buf = ip->image_ptr; buf_offs = -ip->length;
  303.   line_ptr = line_buf = ip->image_adr;
  304.   output = ip->output;
  305.   do
  306.   { /* Level-3 output loop equals Level-2
  307.      * (different initializations).
  308.      * So look at the below Level-2 code for comments.
  309.      */
  310.     char *line_lim0 = line_buf + 256;
  311.     if (line_lim0 > endl_buf) line_lim0 = endl_buf;
  312.     do
  313.     { char *start_ptr = line_buf;
  314.       s_save = -1;
  315.       if ((cdata = *line_buf) == 0 || cdata == -1)
  316.       {
  317.     char *line_lim = line_buf + 127;
  318.     while (line_buf < endl_buf)
  319.     {
  320.       if (*line_buf != cdata)
  321.       {
  322.         cdata = ~cdata;
  323.         if (*line_buf != cdata) break;
  324.         line_lim = line_buf;
  325.       }
  326.       if (line_buf >= line_lim)
  327.       {
  328.         s_save -= 1; line_lim += 127;
  329.       }
  330.       line_buf++;
  331.     }
  332.     cdata = *start_ptr;
  333.       }
  334.       srp = line_buf; line_buf = start_ptr;
  335.       s_save += srp - line_buf;
  336.       if (line_buf != line_ptr && srp < line_lim0) s_save -= 2;
  337.       if (line_buf < endl_buf - 1)
  338.       {
  339.     char *line_lim = line_buf + 255 * 2;
  340.     if (line_lim > endl_buf) line_lim = endl_buf;
  341.     --line_lim;
  342.     c_val = line_buf[1];
  343.     while (line_buf < line_lim &&
  344.            line_buf[0] == cdata &&
  345.            line_buf[1] == c_val) line_buf += 2;
  346.       }
  347.       prp = line_buf; line_buf = start_ptr;
  348.       p_save = (prp - line_buf) - 4;
  349.       if (line_buf != line_ptr && prp < line_lim0) p_save -= 2;
  350.       v_save = -3;
  351.       {
  352.     char *line_lim = line_buf + 255;
  353.     while (line_buf < endl_buf &&
  354.            line_buf[0] == line_buf[buf_offs])
  355.     {
  356.       if (line_buf >= line_lim)
  357.       {
  358.         v_save -= 3; line_lim += 255;
  359.       }
  360.       line_buf++;
  361.       } }
  362.       vrp = line_buf; line_buf = start_ptr;
  363.       v_save += vrp - line_buf;
  364.       if (line_buf != line_ptr && vrp < line_lim0) v_save -= 2;
  365.     }
  366.     while (s_save < 0 && p_save < 0 && v_save < 0 &&
  367.        ++line_buf < line_lim0);
  368.     if (line_buf != line_ptr)
  369.     {
  370.       FPUTC(output, 0x80);
  371.       FPUTC(output, (char)(line_buf - line_ptr));
  372.       do FPUTC(output, *line_ptr++);
  373.       while (line_ptr < line_buf);
  374.     }
  375.     if (s_save >= 0 && s_save >= p_save && s_save >= v_save)
  376.     {
  377.       char *line_lim = line_buf + 127;
  378.       if (line_lim > endl_buf) line_lim = endl_buf;
  379.       while (line_buf < line_lim && *line_buf == cdata) line_buf++;
  380.       cdata <<= 7;
  381.       FPUTC(output, cdata | (char)(line_buf - line_ptr));
  382.       line_ptr = line_buf;
  383.     }
  384.     else if (p_save >= 0 && p_save >= v_save)
  385.     {
  386.       FPUTC(output, 0);
  387.       FPUTC(output, (char)((prp - line_buf) >> 1));
  388.       FPUTC(output, cdata);
  389.       FPUTC(output, c_val);
  390.       line_ptr = line_buf = prp;
  391.     }
  392.     else if (v_save >= 0)
  393.     {
  394.       line_buf += 255;
  395.       if (line_buf > vrp) line_buf = vrp;
  396.       FPUTC(output, 0);
  397.       FPUTC(output, 0);
  398.       FPUTC(output, (char)(line_buf - line_ptr) - 1);
  399.       line_ptr = line_buf;
  400.   } }
  401.   while (line_buf < endl_buf);
  402.  
  403.   ip->image_adr = ip->image_ptr;
  404. }
  405.  
  406. static void l_3_p_1_encode(IBUF *ip)
  407. {
  408.   char cdata, *line_buf, *line_ptr, *endl_buf;
  409.   long s_save, p_save, v_save, buf_offs;
  410.   char *srp, *prp, *vrp;
  411.   FBUFPUB *output;
  412.  
  413.   endl_buf = ip->image_ptr; buf_offs = -ip->length;
  414.   line_ptr = line_buf = ip->image_adr;
  415.   output = ip->output;
  416.   do
  417.   { /* Level-3 output loop equals Level-2
  418.      * (different initializations).
  419.      * So look at the below Level-2 code for comments.
  420.      */
  421.     char *line_lim0 = line_buf + 256;
  422.     if (line_lim0 > endl_buf) line_lim0 = endl_buf;
  423.     do
  424.     { char *start_ptr = line_buf;
  425.       s_save = -1;
  426.       if ((cdata = *line_buf) == 0 || cdata == -1)
  427.       {
  428.     char *line_lim = line_buf + 127;
  429.     while (line_buf < endl_buf)
  430.     {
  431.       if (*line_buf != cdata)
  432.       {
  433.         cdata = ~cdata;
  434.         if (*line_buf != cdata) break;
  435.         line_lim = line_buf;
  436.       }
  437.       if (line_buf >= line_lim)
  438.       {
  439.         s_save -= 1; line_lim += 127;
  440.       }
  441.       line_buf++;
  442.     }
  443.     cdata = *start_ptr;
  444.       }
  445.       srp = line_buf; line_buf = start_ptr;
  446.       s_save += srp - line_buf;
  447.       if (line_buf != line_ptr && srp < line_lim0) s_save -= 2;
  448.       {
  449.     char *line_lim = line_buf + 255;
  450.     if (line_lim > endl_buf) line_lim = endl_buf;
  451.     while (line_buf < line_lim && *line_buf == cdata)
  452.       line_buf++;
  453.     prp = line_buf; line_buf = start_ptr;
  454.     p_save = (prp - line_buf) - 3;
  455.     if (line_buf != line_ptr && prp < line_lim0) p_save -= 2;
  456.       }
  457.       v_save = -3;
  458.       {
  459.     char *line_lim = line_buf + 255;
  460.     while (line_buf < endl_buf &&
  461.            line_buf[0] == line_buf[buf_offs])
  462.     {
  463.       if (line_buf >= line_lim)
  464.       {
  465.         v_save -= 3; line_lim += 255;
  466.       }
  467.       line_buf++;
  468.       } }
  469.       vrp = line_buf; line_buf = start_ptr;
  470.       v_save += vrp - line_buf;
  471.       if (line_buf != line_ptr && vrp < line_lim0) v_save -= 2;
  472.     }
  473.     while (s_save < 0 && p_save < 0 && v_save < 0 &&
  474.        ++line_buf < line_lim0);
  475.     if (line_buf != line_ptr)
  476.     {
  477.       FPUTC(output, 0x80);
  478.       FPUTC(output, (char)(line_buf - line_ptr));
  479.       do FPUTC(output, *line_ptr++);
  480.       while (line_ptr < line_buf);
  481.     }
  482.     if (s_save >= 0 && s_save >= p_save && s_save >= v_save)
  483.     {
  484.       char *line_lim = line_buf + 127;
  485.       if (line_lim > endl_buf) line_lim = endl_buf;
  486.       while (line_buf < line_lim && *line_buf == cdata) line_buf++;
  487.       cdata <<= 7;
  488.       FPUTC(output, cdata | (char)(line_buf - line_ptr));
  489.       line_ptr = line_buf;
  490.     }
  491.     else if (p_save >= 0 && p_save >= v_save)
  492.     {
  493.       FPUTC(output, 0);
  494.       FPUTC(output, (char)(prp - line_buf));
  495.       FPUTC(output, cdata);
  496.       line_ptr = line_buf = prp;
  497.     }
  498.     else if (v_save >= 0)
  499.     {
  500.       line_buf += 255;
  501.       if (line_buf > vrp) line_buf = vrp;
  502.       FPUTC(output, 0);
  503.       FPUTC(output, 0);
  504.       FPUTC(output, (char)(line_buf - line_ptr) - 1);
  505.       line_ptr = line_buf;
  506.   } }
  507.   while (line_buf < endl_buf);
  508.  
  509.   ip->image_adr = ip->image_ptr;
  510. }
  511.  
  512. static void level_3_putline(IBUF *ip)
  513. {
  514.   char *line_buf, *line_ptr, *endl_buf;
  515.   FBUFPUB *output;
  516.  
  517.   line_buf = ip->line_adr;
  518.   endl_buf = ip->pub.pbuf;
  519.   output = ip->output;
  520.  
  521.   if (ip->pub.init == 0)
  522.   {
  523.     ip->pub.init++;
  524.     line_ptr = endl_buf;
  525.     /* Make a complement copy of the first line. This is a trick
  526.      * to avoid special casing extended vrc checking for the first
  527.      * line in the raw encoder.
  528.      */
  529.     do *line_ptr++ = ~*line_buf++;
  530.     while (line_buf < endl_buf);
  531.     goto mark3;
  532.   }
  533.   line_ptr = ip->image_ptr;
  534.   do
  535.     if (*line_ptr++ != *line_buf++)
  536.     {
  537.       if (ip->out_vrc != 1) goto mark1;
  538.       goto mark2;
  539.     }
  540.   while (line_buf < endl_buf);
  541.  
  542.   do
  543.   { if (ip->out_vrc == 256)
  544.     {
  545.       mark1:
  546.       if (ip->image_ptr != ip->image_adr)
  547.     (*ip->raw_encode)(ip);
  548.       FPUTC(output, 0); FPUTC(output, 0);
  549.       FPUTC(output, 0xFF);
  550.       FPUTC(output, (char)ip->out_vrc);
  551.       mark2:
  552.       line_ptr = ip->image_ptr;
  553.       line_ptr += ip->length;
  554.       mark3:
  555.       line_buf = ip->line_adr;
  556.       ip->image_ptr = line_ptr;
  557.       do *line_ptr++ = *line_buf++;
  558.       while (line_buf < endl_buf);
  559.       ip->out_vrc = 0;
  560.     }
  561.     ip->out_vrc++;
  562.     if (--ip->height <= 0)
  563.     {
  564.       if (ip->out_vrc != 1)
  565.       {
  566.     if (ip->image_ptr != ip->image_adr)
  567.       (*ip->raw_encode)(ip);
  568.     FPUTC(output, 0); FPUTC(output, 0);
  569.     FPUTC(output, 0xFF);
  570.     FPUTC(output, (char)ip->out_vrc);
  571.       }
  572.       ip->image_ptr += ip->length;
  573.       (*ip->raw_encode)(ip);
  574.       (*ip->user_exit)();
  575.   } }
  576.   while (--ip->pub.vrc);
  577.   ip->pub.vrc++;
  578.  
  579.   ip->pub.pbuf = ip->line_adr; ip->pub.bytes_left = ip->length;
  580. }
  581.  
  582. static void l_2_p_2_encode(IBUF *ip)
  583. {
  584.   char cdata, c_val, *line_buf, *line_ptr, *endl_buf;
  585.   long s_save, p_save, v_save, buf_offs;
  586.   char *srp, *prp, *vrp;
  587.   FBUFPUB *output;
  588.  
  589.   output = ip->output;
  590.   if (ip->out_vrc != 1)
  591.   {
  592.     FPUTC(output, 0); FPUTC(output, 0);
  593.     FPUTC(output, 0xFF); FPUTC(output, (char)ip->out_vrc);
  594.   }
  595.   /* OK, here's the heart of the Level-2 encoder...
  596.    * The outer loop (within full-line loop) is set up for
  597.    * simple (uncompressed) bytestring handling.
  598.    * "line_ptr" points to next byte to write, "line_buf"
  599.    * is a preview pointer to check for possible _s_olid,
  600.    * _p_attern, or _v_ertical run compression.
  601.    */
  602.   endl_buf = ip->image_adr; buf_offs = ip->length;
  603.   line_ptr = line_buf = ip->pub.pbuf;
  604.   do
  605.   { /* "line_lim0" is set as limit for bytestring handler.
  606.      * NOTE: The offset 256 is the maximum Level-2 bytestring
  607.      * counter, which results in a zero byte value if reached.
  608.      * For Level-1 (compatibility) the maximum offset is 255.
  609.      */
  610.     char *line_lim0 = line_buf + 256;
  611.     if (line_lim0 > endl_buf) line_lim0 = endl_buf;
  612.     do
  613.     { char *start_ptr = line_buf;
  614.       s_save = -1;
  615.       if ((cdata = *line_buf) == 0 || cdata == -1)
  616.       {
  617.     char *line_lim = line_buf + 127;
  618.     while (line_buf < endl_buf)
  619.     {
  620.       if (*line_buf != cdata)
  621.       {
  622.         cdata = ~cdata;
  623.         if (*line_buf != cdata) break;
  624.         line_lim = line_buf;
  625.       }
  626.       if (line_buf >= line_lim)
  627.       {
  628.         s_save -= 1; line_lim += 127;
  629.       }
  630.       line_buf++;
  631.     }
  632.     cdata = *start_ptr;
  633.       }
  634.       srp = line_buf; line_buf = start_ptr;
  635.       s_save += srp - line_buf;
  636.       if (line_buf != line_ptr && srp < line_lim0) s_save -= 2;
  637.       if (line_buf < endl_buf - 1)
  638.       {
  639.     char *line_lim = line_buf + 255 * 2;
  640.     if (line_lim > endl_buf) line_lim = endl_buf;
  641.     --line_lim;
  642.     c_val = line_buf[1];
  643.     while (line_buf < line_lim &&
  644.            line_buf[0] == cdata &&
  645.            line_buf[1] == c_val) line_buf += 2;
  646.       }
  647.       prp = line_buf; line_buf = start_ptr;
  648.       p_save = (prp - line_buf) - 4;
  649.       if (line_buf != line_ptr && prp < line_lim0) p_save -= 2;
  650.       v_save = -3;
  651.       {
  652.     char *line_lim = line_buf + 255;
  653.     while (line_buf < endl_buf &&
  654.            line_buf[0] == line_buf[buf_offs])
  655.     {
  656.       if (line_buf >= line_lim)
  657.       {
  658.         v_save -= 3; line_lim += 255;
  659.       }
  660.       line_buf++;
  661.       } }
  662.       vrp = line_buf; line_buf = start_ptr;
  663.       v_save += vrp - line_buf;
  664.       if (line_buf != line_ptr && vrp < line_lim0) v_save -= 2;
  665.     }
  666.     while (s_save < 0 && p_save < 0 && v_save < 0 &&
  667.        ++line_buf < line_lim0);
  668.     if (line_buf != line_ptr)
  669.     {
  670.       FPUTC(output, 0x80);
  671.       FPUTC(output, (char)(line_buf - line_ptr));
  672.       do FPUTC(output, *line_ptr++);
  673.       while (line_ptr < line_buf);
  674.     }
  675.     if (s_save >= 0 && s_save >= p_save && s_save >= v_save)
  676.     {
  677.       char *line_lim = line_buf + 127;
  678.       if (line_lim > endl_buf) line_lim = endl_buf;
  679.       while (line_buf < line_lim && *line_buf == cdata) line_buf++;
  680.       cdata <<= 7;
  681.       FPUTC(output, cdata | (char)(line_buf - line_ptr));
  682.       line_ptr = line_buf;
  683.     }
  684.     else if (p_save >= 0 && p_save >= v_save)
  685.     {
  686.       FPUTC(output, 0);
  687.       FPUTC(output, (char)((prp - line_buf) >> 1));
  688.       FPUTC(output, cdata);
  689.       FPUTC(output, c_val);
  690.       line_ptr = line_buf = prp;
  691.     }
  692.     else if (v_save >= 0)
  693.     {
  694.       line_buf += 255;
  695.       if (line_buf > vrp) line_buf = vrp;
  696.       FPUTC(output, 0);
  697.       FPUTC(output, 0);
  698.       FPUTC(output, (char)(line_buf - line_ptr) - 1);
  699.       line_ptr = line_buf;
  700.   } }
  701.   while (line_buf < endl_buf);
  702.   /*
  703.    * End of Level-2 encoder.
  704.    */
  705.  
  706.   line_buf = ip->pub.pbuf;
  707.   line_ptr = endl_buf;
  708.   do *line_ptr++ = *line_buf++;
  709.   while (line_buf < endl_buf);
  710. }
  711.  
  712. static void l_2_p_1_encode(IBUF *ip)
  713. {
  714.   char cdata, *line_buf, *line_ptr, *endl_buf;
  715.   long s_save, p_save, v_save, buf_offs;
  716.   char *srp, *prp, *vrp;
  717.   FBUFPUB *output;
  718.  
  719.   output = ip->output;
  720.   if (ip->out_vrc != 1)
  721.   {
  722.     FPUTC(output, 0); FPUTC(output, 0);
  723.     FPUTC(output, 0xFF); FPUTC(output, (char)ip->out_vrc);
  724.   }
  725.   /* OK, here's the heart of the Level-2 encoder...
  726.    * The outer loop (within full-line loop) is set up for
  727.    * simple (uncompressed) bytestring handling.
  728.    * "line_ptr" points to next byte to write, "line_buf"
  729.    * is a preview pointer to check for possible _s_olid,
  730.    * _p_attern, or _v_ertical run compression.
  731.    */
  732.   endl_buf = ip->image_adr; buf_offs = ip->length;
  733.   line_ptr = line_buf = ip->pub.pbuf;
  734.   do
  735.   { /* "line_lim0" is set as limit for bytestring handler.
  736.      * NOTE: The offset 256 is the maximum Level-2 bytestring
  737.      * counter, which results in a zero byte value if reached.
  738.      * For Level-1 (compatibility) the maximum offset is 255.
  739.      */
  740.     char *line_lim0 = line_buf + 256;
  741.     if (line_lim0 > endl_buf) line_lim0 = endl_buf;
  742.     do
  743.     { char *start_ptr = line_buf;
  744.       s_save = -1;
  745.       if ((cdata = *line_buf) == 0 || cdata == -1)
  746.       {
  747.     char *line_lim = line_buf + 127;
  748.     while (line_buf < endl_buf)
  749.     {
  750.       if (*line_buf != cdata)
  751.       {
  752.         cdata = ~cdata;
  753.         if (*line_buf != cdata) break;
  754.         line_lim = line_buf;
  755.       }
  756.       if (line_buf >= line_lim)
  757.       {
  758.         s_save -= 1; line_lim += 127;
  759.       }
  760.       line_buf++;
  761.     }
  762.     cdata = *start_ptr;
  763.       }
  764.       srp = line_buf; line_buf = start_ptr;
  765.       s_save += srp - line_buf;
  766.       if (line_buf != line_ptr && srp < line_lim0) s_save -= 2;
  767.       {
  768.     char *line_lim = line_buf + 255;
  769.     if (line_lim > endl_buf) line_lim = endl_buf;
  770.     while (line_buf < line_lim && *line_buf == cdata)
  771.       line_buf++;
  772.     prp = line_buf; line_buf = start_ptr;
  773.     p_save = (prp - line_buf) - 3;
  774.     if (line_buf != line_ptr && prp < line_lim0) p_save -= 2;
  775.       }
  776.       v_save = -3;
  777.       {
  778.     char *line_lim = line_buf + 255;
  779.     while (line_buf < endl_buf &&
  780.            line_buf[0] == line_buf[buf_offs])
  781.     {
  782.       if (line_buf >= line_lim)
  783.       {
  784.         v_save -= 3; line_lim += 255;
  785.       }
  786.       line_buf++;
  787.       } }
  788.       vrp = line_buf; line_buf = start_ptr;
  789.       v_save += vrp - line_buf;
  790.       if (line_buf != line_ptr && vrp < line_lim0) v_save -= 2;
  791.     }
  792.     while (s_save < 0 && p_save < 0 && v_save < 0 &&
  793.        ++line_buf < line_lim0);
  794.     if (line_buf != line_ptr)
  795.     {
  796.       FPUTC(output, 0x80);
  797.       FPUTC(output, (char)(line_buf - line_ptr));
  798.       do FPUTC(output, *line_ptr++);
  799.       while (line_ptr < line_buf);
  800.     }
  801.     if (s_save >= 0 && s_save >= p_save && s_save >= v_save)
  802.     {
  803.       char *line_lim = line_buf + 127;
  804.       if (line_lim > endl_buf) line_lim = endl_buf;
  805.       while (line_buf < line_lim && *line_buf == cdata) line_buf++;
  806.       cdata <<= 7;
  807.       FPUTC(output, cdata | (char)(line_buf - line_ptr));
  808.       line_ptr = line_buf;
  809.     }
  810.     else if (p_save >= 0 && p_save >= v_save)
  811.     {
  812.       FPUTC(output, 0);
  813.       FPUTC(output, (char)(prp - line_buf));
  814.       FPUTC(output, cdata);
  815.       line_ptr = line_buf = prp;
  816.     }
  817.     else if (v_save >= 0)
  818.     {
  819.       line_buf += 255;
  820.       if (line_buf > vrp) line_buf = vrp;
  821.       FPUTC(output, 0);
  822.       FPUTC(output, 0);
  823.       FPUTC(output, (char)(line_buf - line_ptr) - 1);
  824.       line_ptr = line_buf;
  825.   } }
  826.   while (line_buf < endl_buf);
  827.   /*
  828.    * End of Level-2 encoder.
  829.    */
  830.  
  831.   line_buf = ip->pub.pbuf;
  832.   line_ptr = endl_buf;
  833.   do *line_ptr++ = *line_buf++;
  834.   while (line_buf < endl_buf);
  835. }
  836.  
  837. static void level_2_putline(IBUF *ip)
  838. {
  839.   char *line_buf, *line_ptr, *endl_buf;
  840.  
  841.   line_buf = ip->line_adr;
  842.   endl_buf = ip->pub.pbuf;
  843.  
  844.   if (ip->pub.init == 0)
  845.   {
  846.     ip->pub.init++;
  847.     ip->out_vrc = 0;
  848.     line_ptr = ip->image_adr;
  849.     /* Make a complement copy of the first line. This is a trick
  850.      * to avoid special casing extended vrc checking for the first
  851.      * line in the raw encoder.
  852.      */
  853.     do *line_ptr++ = ~*line_buf++;
  854.     while (line_buf < endl_buf);
  855.     line_buf = ip->line_adr;
  856.     line_ptr = endl_buf;
  857.   }
  858.   else
  859.   {
  860.     line_ptr = endl_buf;
  861.     do
  862.     { if (*line_ptr != *line_buf)
  863.       {
  864.     (*ip->raw_encode)(ip);
  865.     ip->out_vrc = 0;
  866.     break;
  867.       }
  868.       line_ptr++; line_buf++;
  869.     }
  870.     while (line_buf < endl_buf);
  871.   }
  872.   while (line_buf < endl_buf) *line_ptr++ = *line_buf++;
  873.  
  874.   do
  875.   { if (ip->out_vrc == 256)
  876.     {
  877.       (*ip->raw_encode)(ip);
  878.       ip->out_vrc = 0;
  879.     }
  880.     ip->out_vrc++;
  881.     if (--ip->height <= 0)
  882.     {
  883.       (*ip->raw_encode)(ip);
  884.       (*ip->user_exit)();
  885.   } }
  886.   while (--ip->pub.vrc);
  887.   ip->pub.vrc++;
  888.  
  889.   ip->pub.pbuf = ip->line_adr; ip->pub.bytes_left = ip->length;
  890. }
  891.  
  892. static void l_1_p_2_encode(IBUF *ip)
  893. {
  894.   char cdata, c_val, *line_buf, *line_ptr, *endl_buf, *start_ptr;
  895.   FBUFPUB *output;
  896.   int i;
  897.  
  898.   output = ip->output;
  899.   if (ip->out_vrc != 1)
  900.   {
  901.     FPUTC(output, 0); FPUTC(output, 0);
  902.     FPUTC(output, 0xFF); FPUTC(output, (char)ip->out_vrc);
  903.   }
  904.   line_ptr = line_buf = ip->pub.pbuf;
  905.   do
  906.   { endl_buf = line_buf + ip->byte_width;
  907.     do
  908.     { char *line_lim0 = line_buf + 255;
  909.       if (line_lim0 > endl_buf) line_lim0 = endl_buf;
  910.       do
  911.       { if ((cdata = *line_buf++) == 0 || cdata == -1)
  912.     {
  913.       char *line_lim = --line_buf + 127;
  914.       if (line_lim > endl_buf) line_lim = endl_buf;
  915.       start_ptr = line_buf;
  916.       while (line_buf < line_lim && *line_buf == cdata)
  917.         line_buf++;
  918.       i = (int)(line_buf - start_ptr);
  919.       if (i >= 3 || start_ptr == line_ptr ||
  920.           line_buf >= line_lim0)
  921.       {
  922.         entry:
  923.         if (start_ptr != line_ptr)
  924.         {
  925.           FPUTC(output, 0x80);
  926.           FPUTC(output, (char)(start_ptr - line_ptr));
  927.           do FPUTC(output, *line_ptr++);
  928.           while (line_ptr < start_ptr);
  929.         }
  930.         cdata <<= 7; cdata |= (char)i;
  931.         FPUTC(output, cdata);
  932.         line_ptr = line_buf = start_ptr + i;
  933.         break;
  934.       }
  935.       if (i == 2)
  936.         for (;;)
  937.         {
  938.           char cval2;
  939.           if ((c_val = *line_buf++) == 0 || c_val == -1)
  940.           {
  941.         if (line_buf >= line_lim0) goto entry;
  942.         if (*line_buf == c_val) goto entry;
  943.           }
  944.           else
  945.           {
  946.         if (line_buf >= line_lim0 - 2) break;
  947.         if (c_val != line_buf[1]) break;
  948.         cval2 = line_buf[0];
  949.         if (cval2 != line_buf[2]) break;
  950.         if (line_buf >= line_lim0 - 3) goto entry;
  951.         if (line_buf < line_lim0 - 4 &&
  952.             line_buf[3] == c_val &&
  953.             line_buf[4] == cval2) goto entry;
  954.         } }
  955.       line_buf = start_ptr + 1;
  956.     }
  957.     if (line_buf < endl_buf - 2 &&
  958.         cdata == line_buf[1])
  959.     {
  960.       c_val = line_buf[0];
  961.       if (c_val == line_buf[2])
  962.       {
  963.         char *line_lim = --line_buf + 255 * 2;
  964.         if (line_lim > endl_buf) line_lim = endl_buf;
  965.         start_ptr = line_buf;
  966.         --line_lim;
  967.         while (line_buf < line_lim &&
  968.            line_buf[0] == cdata &&
  969.            line_buf[1] == c_val) line_buf += 2;
  970.         i = (int)(line_buf - start_ptr) >> 1;
  971.         if (i >= 3 || start_ptr == line_ptr ||
  972.         line_buf >= line_lim0)
  973.         {
  974.           if (start_ptr != line_ptr)
  975.           {
  976.         FPUTC(output, 0x80);
  977.         FPUTC(output, (char)(start_ptr - line_ptr));
  978.         do FPUTC(output, *line_ptr++);
  979.         while (line_ptr < start_ptr);
  980.           }
  981.           FPUTC(output, 0);
  982.           FPUTC(output, (char)i);
  983.           FPUTC(output, cdata);
  984.           FPUTC(output, c_val);
  985.           line_ptr = line_buf; break;
  986.         }
  987.         line_buf = start_ptr + 1;
  988.       } } }
  989.       while (line_buf < line_lim0);
  990.       if (line_buf != line_ptr)
  991.       {
  992.     FPUTC(output, 0x80);
  993.     FPUTC(output, (char)(line_buf - line_ptr));
  994.     do FPUTC(output, *line_ptr++);
  995.     while (line_ptr < line_buf);
  996.     } }
  997.     while (line_buf < endl_buf);
  998.   }
  999.   while (endl_buf < ip->image_adr);
  1000. }
  1001.  
  1002. static void l_1_p_1_encode(IBUF *ip)
  1003. {
  1004.   char cdata, c_val, *line_buf, *line_ptr, *endl_buf, *start_ptr;
  1005.   FBUFPUB *output;
  1006.   int i;
  1007.  
  1008.   output = ip->output;
  1009.   if (ip->out_vrc != 1)
  1010.   {
  1011.     FPUTC(output, 0); FPUTC(output, 0);
  1012.     FPUTC(output, 0xFF); FPUTC(output, (char)ip->out_vrc);
  1013.   }
  1014.   line_ptr = line_buf = ip->pub.pbuf;
  1015.   do
  1016.   { endl_buf = line_buf + ip->byte_width;
  1017.     do
  1018.     { char *line_lim0 = line_buf + 255;
  1019.       if (line_lim0 > endl_buf) line_lim0 = endl_buf;
  1020.       do
  1021.       { if ((cdata = *line_buf++) == 0 || cdata == -1)
  1022.     {
  1023.       char *line_lim = --line_buf + 127;
  1024.       if (line_lim > endl_buf) line_lim = endl_buf;
  1025.       start_ptr = line_buf;
  1026.       while (line_buf < line_lim && *line_buf == cdata)
  1027.         line_buf++;
  1028.       i = (int)(line_buf - start_ptr);
  1029.       if (i >= 3 || start_ptr == line_ptr ||
  1030.           line_buf >= line_lim0)
  1031.       {
  1032.         put_solid:
  1033.         if (start_ptr != line_ptr)
  1034.         {
  1035.           FPUTC(output, 0x80);
  1036.           FPUTC(output, (char)(start_ptr - line_ptr));
  1037.           do FPUTC(output, *line_ptr++);
  1038.           while (line_ptr < start_ptr);
  1039.         }
  1040.         cdata <<= 7; cdata |= (char)i;
  1041.         FPUTC(output, cdata);
  1042.         line_ptr = line_buf = start_ptr + i;
  1043.         break;
  1044.       }
  1045.       if (i == 2)
  1046.         for (;;)
  1047.           if ((c_val = *line_buf++) == 0 || c_val == -1)
  1048.           {
  1049.         if (line_buf >= line_lim0) goto put_solid;
  1050.         if (*line_buf == c_val) goto put_solid;
  1051.           }
  1052.           else
  1053.           {
  1054.         if (line_buf >= line_lim0 - 1) break;
  1055.         if (c_val != line_buf[0]) break;
  1056.         if (c_val != line_buf[1]) break;
  1057.         if (line_buf >= line_lim0 - 2) goto put_solid;
  1058.         if (c_val == line_buf[2]) goto put_solid;
  1059.           }
  1060.         line_buf = start_ptr + 1;
  1061.     }
  1062.     if (line_buf < endl_buf - 1 &&
  1063.         cdata == line_buf[0] &&
  1064.         cdata == line_buf[1])
  1065.     {
  1066.       char *line_lim = --line_buf + 255;
  1067.       if (line_lim > endl_buf) line_lim = endl_buf;
  1068.       start_ptr = line_buf;
  1069.       while (line_buf < line_lim && *line_buf == cdata)
  1070.         line_buf++;
  1071.       i = (int)(line_buf - start_ptr);
  1072.       if (i >= 5 || start_ptr == line_ptr ||
  1073.           line_buf >= line_lim0)
  1074.       {
  1075.         put_pattern:
  1076.         if (start_ptr != line_ptr)
  1077.         {
  1078.           FPUTC(output, 0x80);
  1079.           FPUTC(output, (char)(start_ptr - line_ptr));
  1080.           do FPUTC(output, *line_ptr++);
  1081.           while (line_ptr < start_ptr);
  1082.         }
  1083.         FPUTC(output, 0);
  1084.         FPUTC(output, (char)i);
  1085.         FPUTC(output, cdata);
  1086.         line_ptr = line_buf = start_ptr + i;
  1087.         break;
  1088.       }
  1089.       if (i == 4)
  1090.         for (;;)
  1091.           if ((c_val = *line_buf++) == 0 || c_val == -1)
  1092.           {
  1093.         if (line_buf >= line_lim0) goto put_pattern;
  1094.         if (*line_buf == c_val) goto put_pattern;
  1095.           }
  1096.           else
  1097.           {
  1098.         if (line_buf >= line_lim0 - 1) break;
  1099.         if (c_val != line_buf[0]) break;
  1100.         if (c_val != line_buf[1]) break;
  1101.         if (line_buf >= line_lim0 - 2) goto put_pattern;
  1102.         if (c_val == line_buf[2]) goto put_pattern;
  1103.           }
  1104.         line_buf = start_ptr + 1;
  1105.       } }
  1106.       while (line_buf < line_lim0);
  1107.       if (line_buf != line_ptr)
  1108.       {
  1109.     FPUTC(output, 0x80);
  1110.     FPUTC(output, (char)(line_buf - line_ptr));
  1111.     do FPUTC(output, *line_ptr++);
  1112.     while (line_ptr < line_buf);
  1113.     } }
  1114.     while (line_buf < endl_buf);
  1115.   }
  1116.   while (endl_buf < ip->image_adr);
  1117. }
  1118.  
  1119. static void level_1_putline(IBUF *ip)
  1120. {
  1121.   char *line_buf, *line_ptr, *endl_buf;
  1122.  
  1123.   line_buf = ip->line_adr;
  1124.   endl_buf = ip->pub.pbuf;
  1125.   line_ptr = endl_buf;
  1126.  
  1127.   if (ip->pub.init == 0)
  1128.   {
  1129.     ip->pub.init++;
  1130.     ip->out_vrc = 0;
  1131.   }
  1132.   else
  1133.     do
  1134.     { if (*line_ptr != *line_buf)
  1135.       {
  1136.     (*ip->raw_encode)(ip);
  1137.     ip->out_vrc = 0;
  1138.     break;
  1139.       }
  1140.       line_ptr++; line_buf++;
  1141.     }
  1142.     while (line_buf < endl_buf);
  1143.  
  1144.   while (line_buf < endl_buf) *line_ptr++ = *line_buf++;
  1145.  
  1146.   do
  1147.   { if (ip->out_vrc == 255)
  1148.     {
  1149.       (*ip->raw_encode)(ip);
  1150.       ip->out_vrc = 0;
  1151.     }
  1152.     ip->out_vrc++;
  1153.     if (--ip->height <= 0)
  1154.     {
  1155.       (*ip->raw_encode)(ip);
  1156.       (*ip->user_exit)();
  1157.   } }
  1158.   while (--ip->pub.vrc);
  1159.   ip->pub.vrc++;
  1160.  
  1161.   ip->pub.pbuf = ip->line_adr; ip->pub.bytes_left = ip->length;
  1162. }
  1163.